#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <time.h>
#include "client.h"
#include "clstub.h"
#include "clsv.h"
#include "sockcomADT.h"
#include "tickets.h"
#include "../src/parser/cl.h"
#include "error.h"
#include "cypher/cypher.h"

#define	_DEFAULTPORT_	"4500"

connInfoT connInfo;
userInfoT userInfo= {"", ""};

static void siginthandler(int sig);
static int getfilesize(const char * path);
static int mygetch(void);

int
main(int argc, char * argv[])
{
	int end = 0;
	char * inpbuf, * port = _DEFAULTPORT_;
	
	if (argc < 2 || argc > 3)
	{
		printf("Usage: %s RemoteIP [RemotePort]\n", argv[0]);
		return 1;
	}
	if ((inpbuf= malloc(MAXLINE+1)) == NULL)
	{
		fprintf(stderr, "Memory allocation error\n");
		return 1;
	}
	strcpy(connInfo.ip, argv[1]);
	if ( argc == 3 )
		strcpy(connInfo.port, argv[2]);
	else
		strcpy(connInfo.port, _DEFAULTPORT_);
	
	system("clear");
	//start_session(COMM_CLIENT, argv[1], port);
	printf("Welcome!\n\n");
	
	signal(SIGINT, siginthandler);
	while (!end && input(PROMPT, inpbuf))
		end = process_line(inpbuf);
	
	free(inpbuf);
	//end_session();
	return 0;
}

void
login(char * user, int service)
{
	char ch, pass[MAX_PASS+1];
	int i=0, wrong=0;
	
	if (strcmp(userInfo.user, ""))
	{
		printf("Already logged in as: \'%s\'!\n", userInfo.user);
		return;
	}
	printf("Password: ");
	
 	while ((ch = mygetch()) != '\n')
	{
		if (i < sizeof(pass)-1)
			pass[i++] = ch;
		else
			wrong = 1;
	}
	pass[i] = '\0';
	printf("\n");
	
	if (strcmp(userInfo.user, ""))
	{
		printf("Already logged in!\n");
		return;
	}
	
	else if (wrong || strlen(user) > MAX_USER)
	{
		printf("Wrong User or Pass.\n");
		return;
	}
	
	printf("Welcome '%s'!\n", user);
	strcpy(userInfo.user, user);
	strcpy(userInfo.pass, pass);
	strcpy(userInfo.epass, userInfo.pass);
	cypher2(userInfo.epass, MAX_PASS+1, pass);
	
	return;
}


void
changePass(int service)
{
	char ch;
	char oldpass[MAX_PASS+1], newpass1[MAX_PASS+1], newpass2[MAX_PASS+1];
	char enc_oldpass[MAX_EPASS], enc_newpass[MAX_EPASS];
	int aux, i=0, wrong=0, response;
	
	if (!strcmp(userInfo.user, ""))
	{
		printf("Login first!\n");
		return;
	}
	
	printf("Current Password: ");
	for (aux= 0; aux<3 && !wrong; aux++)
	{
 		while ((ch = mygetch()) != '\n')
		{
			if (i < sizeof(newpass2)-1)
				newpass2[i++]= ch;
			else
				wrong= 1;
		}
		newpass2[i]= '\0';
		printf("\n");
		i= 0;
		
		if (wrong)
			printf("Invalid Password (Max: %d chars).\n", MAX_PASS);
		else
		{
			if (aux == 0)
			{
				strcpy(oldpass, newpass2);
				printf("Enter new Password: ");
			}
			else if (aux == 1)
			{
				strcpy(newpass1, newpass2);
				printf("Retype new Password: ");
			}
		}
	}
	if (wrong)
		return;
	
	if (strcmp(newpass1, newpass2))
		printf("Sorry, Passwords do not match.\n");
	
	else
	{
		/* encrypt the passwords */
		printf("oldpass = %s\tnewpass = %s\n", oldpass, newpass1);
		strcpy(enc_oldpass, oldpass);
		strcpy(enc_newpass, newpass1);
		cypher2(enc_oldpass,MAX_PASS+1,oldpass);
		cypher2(enc_newpass,MAX_PASS+1,oldpass);
		
		if( service == _TCP_ && !start_session(COMM_CLIENT) )
		{
			fprintf(stderr, "Sockets creation failed\n");
			return;
		}
		if( !(response= passwd(userInfo.user, enc_oldpass, enc_newpass,
							   service)))
			printf("Wrong Password.\n");
		else if( response == 1 )
			printf("Password succesfully changed.\n");
		else if( response == ERROR_NOT_LOGGED_IN )
			printf("You are not logged in!\n");
		
		if( service == _TCP_ )
			end_session();
	}
	
	return;
}

void
getTicket(char * filename)
{
	STAT status;
	ticketP ticket_pars;
	char enc_filename[MAX_FILENAME];
	
	/* encrypt filename */
	strcpy(enc_filename, filename);
	cypher2(enc_filename, MAX_FILENAME+1, userInfo.pass);
	
	/* request a ticket */
	if ((status = get_ticket(enc_filename, userInfo, &ticket_pars)) < 0)
	{
		//TODO: manejar errores
	}
	else
	{
		decypher2(ticket_pars.id, MAX_TICKET, userInfo.pass);
		printTicketParameters(&ticket_pars);
	}
	
	return;
}

void
useTicket(ticketT id, char * filename)
{
	STAT status;
	char enc_id[MAX_ETICKET];
	FILE * file;
	
	/* encrypt ticket id */
	strcpy(enc_id, id);
	cypher2(enc_id, MAX_TICKET+1, userInfo.pass);
	
	/* open local file */
	if ((file = fopen(filename, "w")) == NULL)
	{
		fprintf(stderr, "Error opening local file\n");
		return;
	}
	
	/* use ticket. downloaded file with be copied to f */
	if ((status = use_ticket(enc_id, userInfo, file)) > 0)
	{
		//TODO: imprimir resultados positivos
	}
	else
	{
		//TODO: manejar errores de use_ticket()
	}
	
	/* close file and return */
	fclose(file);
	return;
}

void
uploadFile(char * filename, char * category)
{
	STAT status;
	int size;
	FILE * f;
	
	/* determine filesize to upload */
	size = getfilesize(filename);
	
	/* open local file to upload */
	if ((f = fopen(filename, "w")) == NULL)
	{
		fprintf(stderr, "Error opening local file\n");
		return;
	}
	
	if ((status = upload(filename, size, category, f)) > 0)
	{
		printf("Upload complete\n");
	}
	else
	{
		//TODO: manejar errores de upload
	}
	
	/* close file and return */
	fclose(f);
	return;
}

void
listCategories(void)
{
	STAT status;
	
	/* request list of categories */
	if ((status = list_categories()) > 0)
	{
		printf("List OK!\n");
	}
	else
	{
		//TODO: manejar errores de list_categories();
	}
	
	return;
}

void
listUsers(void)
{
	STAT status;
	
	/* request list of users */
	if ((status = list_users(userInfo)) > 0)
	{
		printf("List OK!\n");
	}
	else
	{
		//TODO: manejar errores de list_users();
	}
	
	return;
}

void
listFiles(char * category)
{
	STAT status;
	
	/* request list of files for the given category */
	if ((status = list_files(userInfo, category)) > 0)
	{
		printf("List OK!\n");
	}
	else
	{
		//TODO: manejar errores de list_files();
	}
	
	return;
}

/* Extra functions */
static void 
siginthandler(int sig)
{
	end_session();
	printf("\n");
	exit(1);
}

static int
getfilesize(const char * path)
{
	struct stat file_status;
	
	if (stat(path, &file_status) != 0)
	{
		//Error(ERROR_FILESTATUS);
	}
	return file_status.st_size;
}

static int
mygetch(void)
{
	char ch;
	struct termios oldt, newt;
	
	tcgetattr(STDIN_FILENO, &oldt);				/* save */
	newt= oldt;
	newt.c_lflag&= ~(ICANON | ECHO);			/* change settings */
	tcsetattr(STDIN_FILENO, TCSANOW, &newt);	/* set now */
	ch= getchar();
	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);	/* restore now */
	return ch;
}
